#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include "Stats.h"


/*
 *------------------------------------------------------------------
 *
 * Stats --
 *
 *          Constructor
 *
 * Arguments:
 *      None.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *
 *------------------------------------------------------------------
 */
Stats::Stats()
{
    // init state
    memset(trAggr, 0, (sizeof(unsigned long) * (MAX_FLOW_ID + 1)));
    memset(prAggr, 0, (sizeof(unsigned long) * (MAX_FLOW_ID + 1)));
    maxSeenFid = -1;

    // init synchronization
    smutex_init(&mutex);     
}



/*
 *------------------------------------------------------------------
 *
 * ~Stats --
 *
 *          Destructor
 *
 * Arguments:
 *      None.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *------------------------------------------------------------------
 */
Stats::~Stats()
{
    smutex_destroy(&mutex);
}


/*
 *------------------------------------------------------------------
 *
 * update --
 *
 *          Update the count for a stream.
 *
 * Arguments:
 *      int flowId -- the Id of the stream
 *      int count -- the number of bytes sent/received
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *------------------------------------------------------------------
 */
void 
Stats::update(int flowId, int byteCount)
{
  smutex_lock(&mutex);

  assert((flowId >= 0) && (flowId <= MAX_FLOW_ID));
  trAggr[flowId] += byteCount;
  maxSeenFid = (flowId > maxSeenFid) ? flowId : maxSeenFid;

  smutex_unlock(&mutex);
}


/*
 *------------------------------------------------------------------
 *
 * toString --
 *
 *          Return a string of counts separated by ' '.
 *
 * Arguments:
 *      char *buffer -- a buffer into which the string
 *                      should be written
 *      int maxLen -- the number of bytes available in this buffer
 *                    (Caller should always hand in large enough
 *                    buffer; callee should be sure not to write 
 *                    past the end of the buffer!)
 *
 * Results:
 *      Return the pointer to the buffer.
 *
 * Side effects:
 *      None.
 *
 *------------------------------------------------------------------
 */
char *
Stats::toString(char *buffer, int maxLen)
{
  int i;
  int bPos = 0;
  unsigned long totalBytes = 0;
  smutex_lock(&mutex);

  if(21 * (maxSeenFid + 1) <= maxLen) {
    for(i = 0; i < maxSeenFid; ++i) {
      unsigned long diff = trAggr[i] - prAggr[i];
      totalBytes += diff;
      bPos = i * 21;
      sprintf((buffer + bPos), "%20lu ", diff);
    }
    bPos += 21;
    sprintf((buffer + bPos), "%20lu", totalBytes);
    
    // saving current trAggr counts
    memcpy(prAggr, trAggr, (sizeof(unsigned long) * (MAX_FLOW_ID + 1)));
  }
  else {
    assert(0);
    // buffer not big enough. not updating previous traffic counts
  }

  smutex_unlock(&mutex);
  return buffer;
}


/*
 *------------------------------------------------------------------
 *
 * unitTest --
 *
 *          Verify simple things that must be true.
 *
 * Arguments:
 *      None.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *------------------------------------------------------------------
 */
void
Stats::unitTest()
{
  // It simply runs.
  printf("Stats self test passes.\n");
  return;
}
